package com.redxiii.spike.util.html;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.csam.jentities.Entities;

public class HttpHelper {
	
	private static final Logger logger = LoggerFactory.getLogger(HttpHelper.class);
	private DefaultHttpClient httpclient = new DefaultHttpClient();
	private BasicHttpContext context = new BasicHttpContext();
	
	protected String 	host;
	protected int 		port = 80;
	protected String 	login;
	protected String 	password;

	public HttpHelper(String host) {
		this();
		this.host = host;
	}
	
	public void setLogin(String login) {
		this.login = login;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	
	public HttpHelper(String host, String login, String password) {
		this();
		this.host = host;
		this.login = login;
		this.password = password;
		
		reconnect();
	}

	public HttpHelper() {
	}
	
	public void reconnect() {
		if (this.httpclient != null) {
			this.httpclient.getConnectionManager().shutdown();
		}
		this.httpclient = new DefaultHttpClient();
		this.context = new BasicHttpContext();
		
		if (this.login != null || this.password != null) {
			this.httpclient.getCredentialsProvider().setCredentials(
					new AuthScope(this.host, this.port),
					new UsernamePasswordCredentials(this.login, this.password));
			
			this.context.setAttribute("preemptive-auth", new BasicScheme());
			this.httpclient.addRequestInterceptor(getPreemptiveAuth(), 0);
		}
	}
		
	public HttpRequestInterceptor getPreemptiveAuth(){
		return new PreemptiveAuth();
	}
	
	public String makeRequest(String request) {
		return makeRequest(new HttpGet(request));
	}
	
	public String makeRequestOnHost(String request) {
		return makeRequest(new HttpGet("http://" + this.host + "/" + request));
	}
	
	public String makeRequest(HttpRequestBase request) {
		HttpResponse response;
		try{
			httpclient.getConnectionManager().closeExpiredConnections();
			response = httpclient.execute(request, context);
			
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) {
				request.abort();
				return makeRequest(response.getLastHeader("Location").getValue()); 
			}
			if(	response.getStatusLine().getStatusCode() != HttpStatus.SC_OK){
				logger.error("Unexpected failure: {}",response.getStatusLine().toString());
				return null;
			}
			
			HttpEntity entity = response.getEntity();
			if(entity != null){
				return EntityUtils.toString(entity);
			} else{
				return null;
			}
			
			
		} catch(Exception e){
			logger.error("Request fail",e);
			return null;
			
		} finally{
			if (request != null)	
				request.abort();
		}
	}

	public String getInputFieldValue(String htmlBody, String name){
		try{
			int i = htmlBody.indexOf("value=", htmlBody.indexOf("name=\"" + name + "\"")) + 7;
			String value = htmlBody.substring(i, htmlBody.indexOf('"', i));
			Entities e = new Entities();
			return e.parseText(value);
		} catch (Exception e){
			e.printStackTrace();
			return "";
		}
	}
	
	public String getTagPropFieldValue(String htmlBody, String tag, String prop, int start) {
		try{
			String iTag = "<" + tag;
			int i = htmlBody.indexOf(iTag,start) + iTag.length();
			int k = htmlBody.indexOf(prop + "=\"", i);
			int j = k + 2 + prop.length();
			return htmlBody.substring(j, htmlBody.indexOf('"',j));
		} catch (Exception e){
			e.printStackTrace();
			return "";
		}
	}
	
	public String getOptionFieldValue(String htmlBody, String name){
		try{
			int i = htmlBody.indexOf("name=\"" + name + "\"");
			int v = htmlBody.indexOf("selected=\"selected\"", i) + 20;
			String value = htmlBody.substring(v, htmlBody.indexOf('<', v));
			Entities e = new Entities();
			return e.parseText(value);
		} catch (Exception e){
			e.printStackTrace();
			return "";
		}
	}
	
	public String getTagFieldValue(String htmlBody, String tag, int start) {
		try{
			String iTag = "<" + tag + ">";
			String eTag = "</" + tag + ">";
			int i = htmlBody.indexOf(iTag,start) + iTag.length();
			int f = htmlBody.indexOf(eTag,i);
			return htmlBody.substring(i, f);
		} catch (Exception e){
			e.printStackTrace();
			return "";
		}
	}
}

class PreemptiveAuth implements HttpRequestInterceptor {

	@Override
	public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
		AuthState authState;
        CredentialsProvider credsProvider;
        HttpHost targetHost;
        
        
        authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
        credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
        targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
        
        // If not auth scheme has been initialized yet
        if (authState.getAuthScheme() == null) {
        	AuthScope authScope = new AuthScope(targetHost.getHostName(),targetHost.getPort());
        	// Obtain credentials matching the target host
            Credentials creds = credsProvider.getCredentials(authScope);
            
            // If found, generate BasicScheme preemptively
            if (creds != null) {
            	AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth");
                authState.setAuthScheme(authScheme);
                authState.setCredentials(creds);
            }
        }
	}
	
}